import os
import datetime
import logging
import calendar
from google.appengine.ext.webapp import template
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.api import users
import atom
import gdata.service
import gdata.auth
import gdata.alt.appengine
import gdata.calendar
import gdata.calendar.service

__author__ = 'alvaro.aguirre.o@gmail.com'

class Calendar(db.Model):
  name = db.StringProperty(required=True)
  calendar_id = db.StringProperty(required=True)
  owner = db.UserProperty()

class Payment(db.Model):
  name = db.StringProperty(required=True)
  amount = db.FloatProperty(required=True)  
  location = db.StringProperty(required=True)
  date = db.DateTimeProperty()
  owner = db.UserProperty()
  edit_link = db.TextProperty()

class GoogleCalendar():
    def __init__(self, request):
        self.calendar_service = gdata.calendar.service.CalendarService()
        gdata.alt.appengine.run_on_appengine(self.calendar_service)
        self.request = request
        
    def CreateCalendar(self, name):
        calendar = gdata.calendar.CalendarListEntry()
        calendar.title = atom.Title(text=name)
        calendar.summary = atom.Summary(text='This calendar contains information about your payments')
        calendar.where = gdata.calendar.Where(value_string='Santiago')
        calendar.color = gdata.calendar.Color(value='#2952A3')
        calendar.timezone = gdata.calendar.Timezone(value='America/Los_Angeles')
        calendar.hidden = gdata.calendar.Hidden(value='false')
        new_calendar = None
        try:
            new_calendar = self.calendar_service.InsertCalendar(new_calendar=calendar)
        except gdata.service.RequestError, request_exception:
            request_error = request_exception[0]
            if request_error['status'] == 401 or request_error['status'] == 403:
                self.Error()
            else:
                raise
        return new_calendar    
    
    def CreateEvent(self, calendar, name, amount, date, location):
        event_entry = gdata.calendar.CalendarEventEntry()
        event_entry.title = atom.Title(text=name)
        event_entry.content = atom.Content(text=amount)
        start_time = date
        event_entry.when.append(gdata.calendar.When(start_time=start_time))
        event_entry.where.append(gdata.calendar.Where(value_string=location))
        new_event = None
        try:
          new_event = self.calendar_service.InsertEvent(event_entry, 'http://www.google.com/calendar/feeds/' + calendar + '/private/full')
        except gdata.service.RequestError, request_exception:
            request_error = request_exception[0]
            if request_error['status'] == 401 or request_error['status'] == 403:
                self.Error()
            else:
                raise        
        return new_event
    
    def DeleteEvent(self, event_link):
        new_event = None
        try:
          new_event = self.calendar_service.DeleteEvent(event_link)
        except gdata.service.RequestError, request_exception:
            request_error = request_exception[0]
            if request_error['status'] == 401 or request_error['status'] == 403:
                self.Error()
            else:
                raise        
        return new_event    
       
    def GetAuthSubUrl(self):
        next = 'http://pay-cal.appspot.com/validate'
        scope = 'http://www.google.com/calendar/feeds/'
        secure = False
        session = True
        return self.calendar_service.GenerateAuthSubURL(next, scope, secure, session)
    
    def Validate(self):
        authsub_token = None
        authsub_token = gdata.auth.extract_auth_sub_token_from_url(self.request.request.uri)
        if not isinstance(self.calendar_service.token_store.find_token('http://www.google.com/calendar/feeds/'), gdata.auth.AuthSubToken) and authsub_token:
            if  users.get_current_user():
                new_token = str(authsub_token).split('=')[1]
                self.calendar_service.SetAuthSubToken(new_token)
                self.calendar_service.UpgradeToSessionToken()
                self.calendar_service.token_store.add_token(self.calendar_service.GetAuthSubToken())
                
    def Error(self):
        self.calendar_service.token_store.remove_all_tokens()
        self.request.redirect(str(self.GetAuthSubUrl()))

class BasePage(webapp.RequestHandler):
  title = ''
  
  def write_page_header(self):
    template_values = {
          'title': self.title}
    path = os.path.join(os.path.dirname(__file__), 'templates')
    path = os.path.join(path, 'header.html')
    self.response.out.write(template.render(path, template_values))
    self.write_signin_links()
  
  def write_signin_links(self):
    if users.get_current_user():
      template_values = {
          'signed_in': True,
          'user_link': users.create_logout_url('/')}
    else:
      template_values = {
          'signed_in': False,
          'user_link': users.create_login_url('/')}
    path = os.path.join(os.path.dirname(__file__), 'templates')
    path = os.path.join(path, 'signin.html')
    self.response.out.write(template.render(path, template_values))
  
  def write_page_footer(self):
    template_values = {}
    path = os.path.join(os.path.dirname(__file__), 'templates')
    path = os.path.join(path, 'footer.html')
    self.response.out.write(template.render(path, template_values))

class InitPage(BasePage):
  title = 'PayCal - Manage your payments with Google Calendar'

  def get(self):
    self.write_page_header()
    owned_query = Calendar.gql('WHERE owner = :1', users.get_current_user())
    owned_calendar = owned_query.get()
    path = os.path.join(os.path.dirname(__file__), 'templates')

    page = None
    if owned_calendar:
        page = 'index.html'
        today = datetime.date.today()
        first_day_of_month = datetime.date(today.year, today.month, 1)
        end_day_of_month = datetime.date(today.year, today.month, calendar.monthrange(today.year, today.month)[1])
        payments = Payment.gql('WHERE owner = :1 and  date>=:2 and date <=:3 ORDER BY date desc', users.get_current_user(), first_day_of_month, end_day_of_month)
        total = 0
        for payment in payments:
           total += payment.amount  
        template_values = {'payments':payments, 'total':total}     
    else:
        template_values = {}
        page = 'create-calendar.html'
    
    path = os.path.join(path, page)
    self.response.out.write(template.render(path, template_values))  
    self.write_page_footer()
    
  def post(self):
    owned_query = Calendar.gql('WHERE owner = :1', users.get_current_user())
    owned_calendar = owned_query.get()
    new_event = None  
    if owned_calendar:
      google_calendar = GoogleCalendar(self)
      year = self.request.get('date').split('/')[2]
      month = self.request.get('date').split('/')[1]
      day = self.request.get('date').split('/')[0]
      gdate = year + '-' + month +'-' + day
      new_event = google_calendar.CreateEvent(owned_calendar.calendar_id, self.request.get('name'), self.request.get('amount'), gdate, self.request.get('location'))
    else:
      self.response.out.write('I\'m sorry, you don\'t have any calendar for your payments')
    if new_event:
        new_payment = Payment(name=self.request.get('name'),
                              amount=float(self.request.get('amount')),
                              location=self.request.get('location'),
                              date=datetime.datetime.strptime(self.request.get('date'), '%d/%m/%Y'),
                              owner=users.get_current_user(),
                              edit_link=new_event.GetEditLink().href
                              )
        new_payment.put()
    self.get()   
    
class ValidateTokenPage(BasePage):
  def get(self):
    google_calendar = GoogleCalendar(self)
    google_calendar.Validate()  
    self.redirect('/')    

class CreateCalendar(BasePage):
  title = 'Create a Calendar for your payments'
  
  def get(self):
    self.write_page_header()
    template_values = {}
    path = os.path.join(os.path.dirname(__file__), 'templates')
    path = os.path.join(path, 'create-calendar.html')
    self.response.out.write(template.render(path, template_values))
    self.write_page_footer()
  
  def post(self):
    google_calendar = GoogleCalendar(self)
    new_calendar = google_calendar.CreateCalendar(self.request.get('name'))

    if new_calendar:
        new_calendar = Calendar(name=self.request.get('name'),
                                calendar_id=new_calendar.id.text.split('/')[8],
                                owner=users.get_current_user()
                                )
        new_calendar.put()
        self.redirect('/')


class DeletePayment(BasePage):
  def get(self):
    self.write_page_header()
    id = self.request.get('id')
    self.response.out.write('Are you sure?')
    self.response.out.write('<form action="/delete-payment" method="post">'
        '<input type="hidden" name="id" value="%s"/>'
        '<input type="submit" value="Yes, Delete this event."/></form>' % (id))
    self.write_page_footer()

  def post(self):
    logging.debug('Deleting the event!: %s' % self.request.get('event_id'))
    payment_id = self.request.get('id')
    if payment_id:
      payment = Payment.get_by_id(int(payment_id))
      if payment and users.get_current_user() == payment.owner:
        google_calendar = GoogleCalendar(self)
        google_calendar.DeleteEvent(str(payment.edit_link))  
        payment.delete()
        self.redirect('/')        

application = webapp.WSGIApplication([('/', InitPage),
                                      ('/delete-payment', DeletePayment),
                                      ('/validate', ValidateTokenPage),
                                      ('/create-calendar', CreateCalendar)
                                      ],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
